package com.ruoyi.web.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.framework.web.enums.AbnormalEnum;
import com.ruoyi.framework.web.exception.TadpoleException;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.web.domain.LegalTender;
import com.ruoyi.web.domain.QgPayBank;
import com.ruoyi.web.domain.QgPayBusiness;
import com.ruoyi.web.domain.QgPayWithdrawalDetail;
import com.ruoyi.web.dto.QgPayWithdrawalDetailAddDTO;
import com.ruoyi.web.dto.QgPayWithdrawalDetailRejectDTO;
import com.ruoyi.web.enums.QGPayWithdrawalDetailEnum;
import com.ruoyi.web.mapper.QgPayWithdrawalDetailMapper;
import com.ruoyi.web.mapper.UserCapitalMapper;
import com.ruoyi.web.service.IQgPayWithdrawalDetailService;
import com.ruoyi.web.utils.CommonUtil;
import com.ruoyi.web.utils.RedisCacheUtil;
import com.ruoyi.web.utils.qg_pay.client.QGPayHttpClient;
import com.ruoyi.web.utils.qg_pay.config.QGPayConfig;
import com.ruoyi.web.utils.qg_pay.entity.QGPayCommonRequestParam;
import com.ruoyi.web.utils.qg_pay.entity.QGPayCommonResponse;
import com.ruoyi.web.utils.qg_pay.entity.request.QGPaySingleOrder;
import com.ruoyi.web.utils.qg_pay.entity.response.QGPaySingleOrderRes;
import com.ruoyi.web.utils.qg_pay.utils.QGPayUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * QGPay提现明细Service业务层处理
 *
 * @date 2023-03-15
 */
@Slf4j
@Service
@AllArgsConstructor
public class QgPayWithdrawalDetailServiceImpl implements IQgPayWithdrawalDetailService {
    private final QgPayWithdrawalDetailMapper qgPayWithdrawalDetailMapper;
    private final QGPayHttpClient qgPayHttpClient;
    private final RedisCacheUtil redisCacheUtil;
    private final CommonUtil commonUtil;
    private final ISysConfigService sysConfigService;
    private final UserCapitalMapper userCapitalMapper;
    private final QGPayConfig qgPayConfig;
    private final QGPayUtil qgPayUtil;

    /**
     * 查询QGPay提现明细
     *
     * @param id QGPay提现明细主键
     * @return QGPay提现明细
     */
    @Override
    public QgPayWithdrawalDetail selectQgPayWithdrawalDetailById(Long id) {
        return qgPayWithdrawalDetailMapper.selectQgPayWithdrawalDetailById(id);
    }

    /**
     * 查询QGPay提现明细列表
     *
     * @param qgPayWithdrawalDetail QGPay提现明细
     * @return QGPay提现明细
     */
    @Override
    public List<QgPayWithdrawalDetail> selectQgPayWithdrawalDetailList(QgPayWithdrawalDetail qgPayWithdrawalDetail) {
        List<QgPayWithdrawalDetail> list = qgPayWithdrawalDetailMapper.selectQgPayWithdrawalDetailList(qgPayWithdrawalDetail);

        // 遍历
        list.forEach(i -> {
            // 设置字典项
            i.setStatus(QGPayWithdrawalDetailEnum.Status.findName(i.getStatus()));
        });

        return list;
    }

    /**
     * 新增QGPay提现明细
     *
     * @param qgPayWithdrawalDetail QGPay提现明细
     * @return 结果
     */
    @Override
    public int insertQgPayWithdrawalDetail(QgPayWithdrawalDetail qgPayWithdrawalDetail) {
        qgPayWithdrawalDetail.setCreateTime(DateUtils.getNowDate());
        return qgPayWithdrawalDetailMapper.insertQgPayWithdrawalDetail(qgPayWithdrawalDetail);
    }

    /**
     * 修改QGPay提现明细
     *
     * @param qgPayWithdrawalDetail QGPay提现明细
     * @return 结果
     */
    @Override
    public int updateQgPayWithdrawalDetail(QgPayWithdrawalDetail qgPayWithdrawalDetail) {
        qgPayWithdrawalDetail.setUpdateTime(DateUtils.getNowDate());
        return qgPayWithdrawalDetailMapper.updateQgPayWithdrawalDetail(qgPayWithdrawalDetail);
    }

    /**
     * 批量删除QGPay提现明细
     *
     * @param ids 需要删除的QGPay提现明细主键
     * @return 结果
     */
    @Override
    public int deleteQgPayWithdrawalDetailByIds(Long[] ids) {
        return qgPayWithdrawalDetailMapper.deleteQgPayWithdrawalDetailByIds(ids);
    }

    /**
     * 删除QGPay提现明细信息
     *
     * @param id QGPay提现明细主键
     * @return 结果
     */
    @Override
    public int deleteQgPayWithdrawalDetailById(Long id) {
        return qgPayWithdrawalDetailMapper.deleteQgPayWithdrawalDetailById(id);
    }

    /**
     * 创建提现申请
     *
     * @param dto dto
     * @since 2023/3/22 14:54
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void add(QgPayWithdrawalDetailAddDTO dto) {
        SysUser user = CommonUtil.getLoginUserNotNull();
        // 根据法币编码查询法币
        LegalTender legalTender = redisCacheUtil.getLegalTender(dto.getLegalTenderCode(), false);
        // 根据业务编码查询QGPay业务
        QgPayBusiness qgPayBusiness = redisCacheUtil.getQgPayBusiness(dto.getBusinessCode(), false);

        // 创建充值记录
        QgPayWithdrawalDetail detail = new QgPayWithdrawalDetail();
        detail.setUserId(user.getUserId());
        detail.setLegalTenderName(legalTender.getName());
        detail.setLegalTenderCode(legalTender.getCode());
        detail.setAmount(dto.getAmount());
        detail.setRate(legalTender.getRate());
        detail.setUsdt(QGPayUtil.transferLegalTender2USDT(detail.getAmount(), detail.getRate()));
        // 如果转换为usdt后数量等于0
        if (detail.getUsdt().compareTo(BigDecimal.ZERO) == 0) {
            throw new TadpoleException(AbnormalEnum.MSG.FAILED_TO_CREATE_WITHDRAWAL_REQUEST);
        }

        // 获取法币提现手续费率
        BigDecimal feeRate = qgPayUtil.getWithdrawalFeeRate();
        detail.setFee(detail.getUsdt().multiply(feeRate));

        detail.setActualUsdt(detail.getUsdt().subtract(detail.getFee()));
        detail.setActualAmount(QGPayUtil.transferUSDT2LegalTender(detail.getActualUsdt(), detail.getRate()));
        detail.setReceiptAmount(BigDecimal.ZERO);
        detail.setBusinessName(qgPayBusiness.getName());
        detail.setBusinessCode(qgPayBusiness.getCode());

        if (Strings.isNotBlank(dto.getBankCode())) {
            // 根据银行编码查询QGPay银行
            QgPayBank qgPayBank = redisCacheUtil.getQgPayBank(dto.getBankCode(), false);
            detail.setBankName(qgPayBank.getName());
            detail.setBankCode(dto.getBankCode());

        } else {
            detail.setBankCode("BANK");
        }

        detail.setAccount(dto.getAccount());
        detail.setAccountName(dto.getAccountName());
        detail.setPhone(dto.getPhone());
        detail.setProvince(dto.getProvince());
        detail.setIdentityNo(dto.getIdentityNo());
        detail.setIdentityType(dto.getIdentityType());
        detail.setStatus(QGPayWithdrawalDetailEnum.Status.UN_APPROVE.getValue());
        commonUtil.initCreateAbout(detail, user);

        if (qgPayWithdrawalDetailMapper.insertQgPayWithdrawalDetail(detail) != 1) {
            throw new TadpoleException(AbnormalEnum.MSG.FAILED_TO_CREATE_WITHDRAWAL_REQUEST);
        }

        // 资金账户减少
        if (userCapitalMapper.minusBalance(detail.getUserId(), detail.getUsdt()) != 1) {
            throw new TadpoleException(AbnormalEnum.MSG.INSUFFICIENT_FUND_ACCOUNT);
        }
    }

    /**
     * 审核通过
     *
     * @param id id
     * @since 2023/3/22 16:12
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void approve(Long id) {
        // 修改提现申请状态
        QgPayWithdrawalDetail condition = new QgPayWithdrawalDetail();
        condition.setId(id);
        condition.setStatus(QGPayWithdrawalDetailEnum.Status.ONGOING.getValue());
        commonUtil.initUpdateAbout(condition);
        if (qgPayWithdrawalDetailMapper.approve(condition) != 1) {
            throw new TadpoleException("状态已经发生改变，请刷新重试");
        }

        QgPayWithdrawalDetail detail = qgPayWithdrawalDetailMapper.selectQgPayWithdrawalDetailById(id);
        if (Objects.isNull(detail)) {
            throw new TadpoleException("没有找到提现申请，id：" + id);
        }

        // 创建代付订单
        QGPaySingleOrder body = new QGPaySingleOrder();
        body.setMerchant(qgPayConfig.getMerchant());
        body.setOrderNo(detail.getId());
        body.setBusinessCode(detail.getBusinessCode());
        body.setAccNo(detail.getAccount());
        body.setAccName(detail.getAccountName());
        body.setOrderAmount(detail.getActualAmount());
        body.setBankCode(detail.getBankCode());

        // todo 后续接入其它有特殊要求的国家时，以下内容需要修改
        body.setPhone(Strings.isNotBlank(detail.getPhone()) ? detail.getPhone() : "15112345678");
        body.setProvince(Strings.isNotBlank(detail.getProvince()) ? detail.getProvince() : "province");
        body.setIdentityNo(Strings.isNotBlank(detail.getIdentityNo()) ? detail.getIdentityNo() : "identityNo");
        body.setIdentityType(Strings.isNotBlank(detail.getIdentityType()) ? detail.getIdentityType() : "identityType");
        body.setNotifyUrl(qgPayConfig.getPayNotifyUrl());
        body.setRemake("singleOrder");

        QGPayCommonRequestParam<?, QGPaySingleOrder> param = new QGPaySingleOrder();
        param.setBody(body);
        QGPayCommonResponse<QGPaySingleOrderRes> res = qgPayHttpClient.request(param);
        if (!res.getIsSuccess()) {
            String errorMsg = String.format("QGPay创建代付订单失败，请求参数：%s，返回结果：%s", param.getBody(), res);
            log.error(errorMsg);
            throw new TadpoleException(errorMsg);
        }
    }

    /**
     * 审核拒绝
     *
     * @param dto dto
     * @since 2023/3/22 16:51
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void reject(QgPayWithdrawalDetailRejectDTO dto) {
        // 修改提现申请状态
        QgPayWithdrawalDetail condition = new QgPayWithdrawalDetail();
        condition.setId(dto.getId());
        condition.setRemark(dto.getRemark());
        condition.setStatus(QGPayWithdrawalDetailEnum.Status.REJECT.getValue());
        commonUtil.initUpdateAbout(condition);
        if (qgPayWithdrawalDetailMapper.reject(condition) != 1) {
            throw new TadpoleException("状态已经发生改变，请刷新重试");
        }

        QgPayWithdrawalDetail detail = qgPayWithdrawalDetailMapper.selectQgPayWithdrawalDetailById(dto.getId());
        if (Objects.isNull(detail)) {
            throw new TadpoleException("没有找到提现申请，id：" + dto.getId());
        }

        // 退还资金
        if (userCapitalMapper.addBalance(detail.getUserId(), detail.getUsdt()) != 1) {
            throw new TadpoleException("回滚资金账户额度失败");
        }
    }

    /**
     * QGPay代付通知
     *
     * @param dto 通知
     * @since 2023/3/17 14:21
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void qgSingleOrderNotify(JSONObject dto) {
        // 校验通知参数
        qgPayUtil.validNotify(dto);

        QgPayWithdrawalDetail condition = new QgPayWithdrawalDetail();
        condition.setId(dto.getLongValue("merchantOrderNo"));
        QgPayWithdrawalDetail detail = qgPayWithdrawalDetailMapper.getOneLock(condition);
        // 判断提现明细状态，不是提现中状态时，直接结束，返回SUCCESS
        if (Objects.isNull(detail) || !QGPayWithdrawalDetailEnum.Status.ONGOING.getValue().equals(detail.getStatus())) {
            return;
        }

        boolean isSuccess = "success".equals(dto.getString("status"));
        // 提现成功
        if (isSuccess) {
            BigDecimal payAmount = dto.getBigDecimal("payAmount");
            detail.setReceiptAmount(payAmount);
            detail.setStatus(QGPayWithdrawalDetailEnum.Status.SUCCESS.getValue());

            // 支付失败
        } else {
            detail.setStatus(QGPayWithdrawalDetailEnum.Status.FAIL.getValue());

            // 回滚资金账户
            if (userCapitalMapper.addBalance(detail.getUserId(), detail.getUsdt()) != 1) {
                qgPaySingleOrderHandleFail(dto);
            }
        }

        detail.setUpdateTime(new Date());
        if (qgPayWithdrawalDetailMapper.updateQgPayWithdrawalDetail(detail) != 1) {
            qgPaySingleOrderHandleFail(dto);
        }
    }

    /**
     * 代付回调通知处理失败 统一处理逻辑
     *
     * @param dto 通知
     * @since 2023/3/17 15:05
     */
    private static void qgPaySingleOrderHandleFail(Object dto) {
        log.error("代付回调通知处理失败，通知：{}", dto);
        CommonUtil.throwError();
    }

    /**
     * h5分页查询
     *
     * @param condition 查询条件
     * @return {@link List< QgPayWithdrawalDetail>}
     * @since 2023/3/22 16:58
     */
    @Override
    public List<QgPayWithdrawalDetail> appPage(QgPayWithdrawalDetail condition) {
        SysUser user = CommonUtil.getLoginUserNotNull();
        condition.setUserId(user.getUserId());
        List<QgPayWithdrawalDetail> list = qgPayWithdrawalDetailMapper.selectQgPayWithdrawalDetailList(condition);

        // 遍历
        list.forEach(i -> {
            // 设置字典项
            i.setStatus(QGPayWithdrawalDetailEnum.Status.findName(i.getStatus()));
        });

        return list;
    }
}
